home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint96sb.zoo / src / dosmem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-10  |  28.0 KB  |  1,118 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. /*
  6.  * GEMDOS emulation routines: these are for the GEMDOS system calls
  7.  * concerning allocating/freeing memory, including Pexec() (since
  8.  * this allocates memory) and Pterm() (since this, implicitly, frees
  9.  * it).
  10.  */
  11.  
  12. #include "mint.h"
  13.  
  14. int procdate, proctime;    /* set when any processes are created/destroyed */
  15.  
  16. static long do_vfork P_((int));
  17.  
  18. /*
  19.  * new call for TT TOS, for the user to inform DOS of alternate memory
  20.  * FIXME: we really shouldn't trust the user so completely
  21.  */
  22.  
  23. long ARGS_ON_STACK
  24. m_addalt(start, size)
  25.     long start, size;
  26. {
  27.     if (!add_region(alt, start, size, M_ALT))
  28.         return EINTRN;
  29.     else
  30.         return 0;
  31. }
  32.  
  33. /*
  34.  * internal routine for doing Malloc on a particular memory map
  35.  */
  36.  
  37. long
  38. _do_malloc(map, size, mode)
  39.     MMAP map;
  40.     long size;
  41.     int mode;
  42. {
  43.     virtaddr v;
  44.     MEMREGION *m;
  45.     long maxsize, mleft;
  46.  
  47.     if (size == -1L) {
  48.         maxsize = max_rsize(map);
  49.         if (curproc->maxmem) {
  50.             mleft = curproc->maxmem - memused(curproc);
  51.             if (maxsize > mleft)
  52.                 maxsize = mleft;
  53.             if (maxsize < 0)
  54.                 maxsize = 0;
  55.         }
  56.     /* make sure to round down */
  57.         return maxsize & ~MASKBITS;
  58.     }
  59.  
  60. /* special case: Malloc(0) should always return 0 */
  61.     if (size == 0)
  62.         return 0;
  63.  
  64.     if (curproc->maxmem) {        /* memory limit? */
  65.         if (size > curproc->maxmem - memused(curproc)) {
  66.             DEBUG(("malloc: memory request would exceed limit"));
  67.             return 0;
  68.         }
  69.     }
  70.  
  71.     m = get_region(map, size);
  72.     if (!m) {
  73.         DEBUG(("malloc: out of memory"));
  74.         return 0;
  75.     }
  76.     v = attach_region(curproc, m);
  77.     if (!v) {
  78.         m->links = 0;
  79.         free_region(m);
  80.         return 0;
  81.     }
  82. /* NOTE: get_region returns a region with link count 1; since attach_region
  83.  * increments the link count, we have to remember to decrement the count
  84.  * to correct for this.
  85.  */
  86.     m->links--;
  87.     if ((mode & F_KEEP)) {    /* request for permanent memory */
  88.         m->mflags |= M_KEEP;
  89.     }
  90.     return (long)v;
  91. }
  92.  
  93. long ARGS_ON_STACK
  94. m_xalloc(size, mode)
  95.     long size;
  96.     int mode;
  97. {
  98.     long r, r1;
  99.  
  100.     TRACE(("Mxalloc(%ld,%x)",size,mode));
  101.     if ( (mode & 8) ) {
  102.         DEBUG(("Unsupported Mxalloc mode: %x", mode));
  103.         return 0;        /* future expansion */
  104.     }
  105.     if ( (mode&3) == 0)
  106.         return _do_malloc(core, size, mode);
  107.     else if ( (mode&3) == 1)
  108.         return _do_malloc(alt, size, mode);
  109.     else if (size == -1) {
  110.         /* modes 2 and 3 are the same for for size -1 */
  111.         r = _do_malloc(core, -1L, mode);
  112.         r1 = _do_malloc(alt, -1L, mode);
  113.         if (r > r1) return r;
  114.         else return r1;
  115.     }
  116.     else if ( (mode&3) == 2) {
  117.         r = _do_malloc(core, size, mode);
  118.         if (r == 0) return _do_malloc(alt, size, mode);
  119.         else return r;
  120.     }
  121.     else /* if ( (mode&3) == 3) */ {
  122.         r = _do_malloc(alt, size, mode);
  123.         if (r == 0) return _do_malloc(core, size, mode);
  124.         else return r;
  125.     }
  126. }
  127.  
  128. long ARGS_ON_STACK
  129. m_alloc(size)
  130.     long size;
  131. {
  132.     long r;
  133.  
  134.     TRACE(("Malloc(%lx)", size));
  135.     if (curproc->memflags & F_ALTALLOC)
  136.         r = m_xalloc(size, 3);
  137.     else
  138.         r = m_xalloc(size, 0);
  139.     TRACE(("Malloc: returning %lx", r));
  140.     return r;
  141. }
  142.  
  143. long ARGS_ON_STACK
  144. m_free(block)
  145.     virtaddr block;
  146. {
  147.     MEMREGION *m;
  148.     int i;
  149.  
  150.     TRACE(("Mfree(%lx)", block));
  151.     if (!block) {
  152.         DEBUG(("Mfree: null pointer"));
  153.         return EIMBA;
  154.     }
  155.  
  156. /* search backwards so that most recently allocated incarnations of
  157.    shared memory blocks are freed first (this doesn't matter very often)
  158.  */
  159.  
  160.     for (i = curproc->num_reg - 1; i >= 0; i--) {
  161.         if (curproc->addr[i] == block) {
  162.             m = curproc->mem[i];
  163.             assert(m != NULL);
  164.             assert(m->loc == (long)block);
  165.             curproc->mem[i] = 0;
  166.             curproc->addr[i] = 0;
  167.             m->links--;
  168.             if (m->links == 0) {
  169.                 free_region(m);
  170.             }
  171.             return 0;
  172.         }
  173.     }
  174.  
  175. /* hmmm... if we didn't find the region, perhaps it's a global
  176.  * one (with the M_KEEP flag set) belonging to a process that
  177.  * terminated
  178.  */
  179.     for (i = rootproc->num_reg - 1; i >= 0; i--) {
  180.         if (rootproc->addr[i] == block) {
  181.             m = rootproc->mem[i];
  182.             assert(m != NULL);
  183.             assert(m->loc == (long)block);
  184.             if (!(m->mflags & M_KEEP))
  185.                 continue;
  186.             rootproc->mem[i] = 0;
  187.             rootproc->addr[i] = 0;
  188.             m->links--;
  189.             if (m->links == 0) {
  190.                 free_region(m);
  191.             }
  192.             return 0;
  193.         }
  194.     }
  195.  
  196.  
  197.     DEBUG(("Mfree: bad address %lx", block));
  198.     return EIMBA;
  199. }
  200.  
  201. long ARGS_ON_STACK
  202. m_shrink(dummy, block, size)
  203.     int dummy;
  204.     virtaddr block;
  205.     long size;
  206. {
  207.     MEMREGION *m;
  208.     int i;
  209.  
  210.     UNUSED(dummy);
  211.     TRACE(("Mshrink: %lx to %ld", block, size));
  212.     if (!block) {
  213.         DEBUG(("Mshrink: null pointer"));
  214.         return EIMBA;
  215.     }
  216.  
  217.     for (i = 0; i < curproc->num_reg; i++) {
  218.         if (curproc->addr[i] == block) {
  219.             m = curproc->mem[i];
  220.             assert(m != NULL);
  221.             assert(m->loc == (long)block);
  222.             return shrink_region(m, size);
  223.         }
  224.     }
  225.     DEBUG(("Mshrink: bad address (%lx)", block));
  226.     return EIMBA;
  227. }
  228.  
  229. long ARGS_ON_STACK
  230. p_exec(mode, ptr1, ptr2, ptr3)
  231.     int mode;
  232.     void *ptr1, *ptr2, *ptr3;
  233. {
  234.     MEMREGION *base,
  235.         *env = 0;    /* assignment suppresses spurious warning */
  236.     MEMREGION *text = 0;    /* for shared text regions */
  237.     PROC *p;
  238.     long r, flags = 0;
  239.     int i;
  240.     char mkbase = 0, mkload = 0, mkgo = 0, mkwait = 0, mkfree = 0;
  241.     char overlay = 0;
  242.     char thread = 0;
  243.     char ptrace;
  244.     char mkname = 0, *newname, *lastslash;
  245.     char localname[PNAMSIZ+1];
  246.     XATTR xattr;
  247.  
  248. /* the high bit of mode controls process tracing */
  249.     switch(mode & 0x7fff) {
  250.     case 0:
  251.         mkwait = 1;        /* fall through */
  252.     case 100:
  253.         mkload = mkgo = mkfree = 1;
  254.         mkname = 1;
  255.         TRACE(("Pexec(%d,%s,\"%s\")", mode, ptr1, ptr2));
  256.         break;
  257.     case 200:            /* overlay current process */
  258.         mkload = mkgo = 1;
  259.         overlay = mkname = 1;
  260.         TRACE(("Pexec(%d,%s,\"%s\")", mode, ptr1, ptr2));
  261.         break;
  262.     case 3:
  263.         mkload = 1;
  264.         TRACE(("Pexec(%d,%s,\"%s\")", mode, ptr1, ptr2));
  265.         break;
  266.     case 6:
  267.         mkfree = 1;
  268.         /* fall through */
  269.     case 4:
  270.         mkwait = mkgo = 1;
  271.         TRACE(("Pexec(%d,%lx)", mode, ptr2));
  272.         break;
  273.     case 106:
  274.         mkfree = 1;        /* fall through */
  275.     case 104:
  276.         thread = (mode == 104);
  277.         mkgo = 1;
  278.         mkname = (ptr1 != 0);
  279.         TRACE(("Pexec(%d,%s,%lx)", mode, ptr1, ptr2));
  280.         break;
  281.     case 206:
  282. #if 0
  283.     /* mkfree has no effect when overlay is set, since
  284.      * in this case the "parent" and "child" are the same
  285.      * process; since the "child" will run in memory that the
  286.      * "parent" allocated, we don't want that memory freed!
  287.      */
  288.         mkfree = 1;
  289. #endif
  290.         /* fall through */
  291.     case 204:
  292.         mkgo = overlay = 1;
  293.         mkname = (ptr1 != 0);
  294.         TRACE(("Pexec(%d,%s,%lx)", mode, ptr1, ptr2));
  295.         break;
  296.     case 7:
  297.         flags = (long)ptr1;    /* set program flags */
  298.                     /* and fall through */
  299.     case 5:
  300.         mkbase = 1;
  301.         TRACE(("Pexec(%d,%lx,\"%s\")", mode, ptr1, ptr2));
  302.         break;
  303.     default:
  304.         DEBUG(("Pexec: bad mode %d", mode));
  305.         return EINVFN;
  306.     }
  307.  
  308.     ptrace = (!mkwait && (mode & 0x8000));
  309.  
  310. /* in most cases, we'll want a process struct to exist,
  311.  * so make sure one is around. Note that we must be
  312.  * careful to free it later!
  313.  */
  314.  
  315.     p = 0;
  316.     if (!overlay) {
  317.         p = new_proc();
  318.         if (!p) {
  319.             DEBUG(("Pexec: couldn't get a PROC struct"));
  320.             return ENSMEM;
  321.         }
  322.     }
  323.  
  324.  
  325.     if (mkload || mkbase) {
  326.         env = create_env((char *)ptr3);
  327.         if (!env) {
  328.             DEBUG(("Pexec: unable to create environment"));
  329.             if (p) dispose_proc(p);
  330.             return ENSMEM;
  331.         }
  332.     }
  333.  
  334.     if (mkbase) {
  335.         base = create_base((char *)ptr2, env, flags, 0L);
  336.         if (!base) {
  337.             DEBUG(("Pexec: unable to create basepage"));
  338.             detach_region(curproc, env);
  339.             if (p) dispose_proc(p);
  340.             return ENSMEM;
  341.         }
  342. TRACE(("Pexec: basepage region(%lx) is %ld bytes at %lx", base, base->len, base->loc));
  343.     }
  344.     else if (mkload) {
  345.         base = load_region((char *)ptr1, env, (char *)ptr2,
  346.             &xattr, &text);
  347.         if (!base) {
  348.             DEBUG(("Pexec: load_region failed"));
  349.             detach_region(curproc, env);
  350.             if (p) dispose_proc(p);
  351.             return mint_errno;
  352.         }
  353. TRACE(("Pexec: basepage region(%lx) is %ld bytes at %lx", base, base->len, base->loc));
  354.     }
  355.     else {    /* mode == 4,6,104,106,204, or 206 -- just go */
  356.         base = addr2mem((virtaddr)ptr2);
  357.         if (base)
  358.             env = addr2mem(*(void **)(base->loc + 0x2c));
  359.         else
  360.             env = 0;
  361.         if (!env) {
  362.             if (p) dispose_proc(p);
  363.             return EIMBA;
  364.         }
  365.     }
  366.  
  367. /* make a local copy of the name, in case we are overlaying the current
  368.  * process
  369.  */
  370.     if (mkname) {
  371.         lastslash = 0;
  372.         newname = ptr1;
  373.         while (*newname) {
  374.             if (*newname == '\\' || *newname == '/')
  375.                 lastslash = newname;
  376.             ++newname;
  377.         }
  378.         if (!lastslash)
  379.             lastslash = ptr1;
  380.         else
  381.             lastslash++;
  382.  
  383.         i = 0; newname = localname;
  384.         while (i++ < PNAMSIZ) {
  385.             if (*lastslash == '.' || *lastslash == 0) {
  386.                 *newname = 0; break;
  387.             }
  388.             else
  389.                 *newname++ = *lastslash++;
  390.         }
  391.         *newname = 0;
  392.     }
  393.  
  394.     if (p) {
  395.     /* free the PROC struct so fork_proc will succeed */
  396.         dispose_proc(p);
  397.         p = 0;
  398.     }
  399.  
  400.     if (mkgo) {
  401.         BASEPAGE *b;
  402.  
  403.         if (overlay) {
  404.             p = curproc;
  405.         /* make sure that exec_region doesn't free the base and env */
  406.             base->links++;
  407.             env->links++;
  408.             if (text) text->links++;
  409.         }
  410.         else {
  411.             p = fork_proc();
  412.         }
  413.         if (!p) {
  414.             if (mkbase) {
  415.                 detach_region(curproc, base);
  416.                 detach_region(curproc, env);
  417.                 if (text) detach_region(curproc, text);
  418.             }
  419.             return mint_errno;
  420.         }
  421.         if (ptrace)
  422.             p->ptracer = pid2proc(p->ppid);
  423.  
  424.     /* Even though the file system won't allow unauthorized access
  425.      * to setuid/setgid programs, it's better to err on the side of
  426.      * caution and forbid them to be traced (since the parent can arrange
  427.      * to share the child's address space, not all accesses need to
  428.      * go through the file system!)
  429.      */
  430.         if (mkload && mkgo && !p->ptracer) {    /* setuid/setgid is OK */
  431.             if (xattr.mode & S_ISUID)
  432.                 p->euid = xattr.uid;
  433.             if (xattr.mode & S_ISGID)
  434.                 p->egid = xattr.gid;
  435.         }
  436.         (void)exec_region(p, base, thread);
  437.         attach_region(p, env);
  438.         attach_region(p, base);
  439.         if (text) attach_region(p, text);
  440.  
  441.     /* tell the child who the parent was */
  442.         b = (BASEPAGE *)base->loc;
  443.         if (!overlay)
  444.             b->p_parent = (BASEPAGE *)curproc->base;
  445.  
  446.         if (mkname) {
  447.     /* interesting coincidence -- if a process needs a name, it usually
  448.      * needs to have its domain reset to DOM_TOS. Doing it this way
  449.      * (instead of doing it in exec_region) means that Pexec(4,...)
  450.      * can be used to create new threads of execution which retain
  451.      * the same domain.
  452.      */
  453.             if (!thread)
  454.                 p->domain = DOM_TOS;
  455.  
  456.     /* put in the new process name we saved above */
  457.             strcpy(p->name, localname);
  458.         }
  459.  
  460.     /* turn on tracing for the new process */
  461.         if (p->ptracer)
  462.             p->ctxt[CURRENT].ptrace = 1;
  463.  
  464.     /* set the time/date stamp of u:\proc */
  465.         proctime = timestamp;
  466.         procdate = datestamp;
  467.  
  468.         if (overlay) {
  469.             /* correct for temporary increase in links (see above) */
  470.             base->links--;
  471.             env->links--;
  472.             if (text) text->links--;
  473.             /* let our parent run, if it Vfork'd() */
  474.             if ( (p = pid2proc(curproc->ppid)) != 0 ) {
  475.                 if (p->wait_q == WAIT_Q && 
  476.                     p->wait_cond == (long)curproc) {
  477.                     rm_q(WAIT_Q, p);
  478.                     add_q(READY_Q, p);
  479.                 }
  480.             }
  481.  
  482.         /* OK, let's run our new code */
  483.         /* we guarantee ourselves at least 2 timeslices to do an Mshrink */
  484.             assert(curproc->magic == CTXT_MAGIC);
  485.             fresh_slices(2);
  486.             leave_kernel();
  487.             restore_context(&(curproc->ctxt[CURRENT]));
  488.         }
  489.         else {
  490.     /* we want this process to run ASAP */
  491.     /* so we temporarily give it high priority and put it first on the
  492.      * run queue
  493.      */
  494.             run_next(p, 2);
  495.         }
  496.     }
  497.  
  498.     if (mkfree) {
  499.         detach_region(curproc, base);
  500.         detach_region(curproc, env);
  501.         if (text) detach_region(curproc, text);
  502.     }
  503.  
  504.     if (mkwait) {
  505.         long oldsigint, oldsigquit;
  506.  
  507.         oldsigint = curproc->sighandle[SIGINT];
  508.         oldsigquit = curproc->sighandle[SIGQUIT];
  509.         curproc->sighandle[SIGINT] =
  510.              curproc->sighandle[SIGQUIT] = SIG_IGN;
  511.  
  512.         i = p->pid;
  513.         for(;;) {
  514.             r = p_wait3(0, (long *)0);
  515.             if (r < 0) {
  516.                 ALERT("p_exec: wait error");
  517.                 return EINTRN;
  518.             }
  519.             if ( i == ((r&0xffff0000L) >> 16) ) {
  520.                 TRACE(("leaving Pexec with child return code"));
  521.                 r = r & 0x0000ffffL;
  522.                 break;
  523.             }
  524.             if (curproc->pid)
  525.                 DEBUG(("Pexec: wrong child found"));
  526.         }
  527.         curproc->sighandle[SIGINT] = oldsigint;
  528.         curproc->sighandle[SIGQUIT] = oldsigquit;
  529.         return r;
  530.     }
  531.     else if (mkgo) {
  532.         yield();    /* let the new process run */
  533.         return p->pid;
  534.     } else {
  535.         TRACE(("leaving Pexec with basepage address %lx", base->loc));
  536.         return base->loc;
  537.     }
  538. }
  539.  
  540. /*
  541.  * terminate a process, with return code "code". If que == ZOMBIE_Q, free
  542.  * all resources attached to the child; if que == TSR_Q, free everything
  543.  * but memory.
  544.  * NOTE: terminate() should be called only when the process is to be
  545.  * "terminated with extreme prejuidice". Most times, p_term or p_termres
  546.  * are the functions to use, since they allow the user to do some cleaning
  547.  * up, etc.
  548.  */
  549.  
  550. long
  551. terminate(code, que)
  552.     int code, que;
  553. {
  554.     extern PROC *dlockproc[];    /* in dosdir.c */
  555.     PROC *p;
  556.     FILEPTR *fp;
  557.     MEMREGION *m;
  558.     int  i, wakemint = 0;
  559.     extern short bconbsiz;    /* in bios.c */
  560.  
  561.     if (bconbsiz)
  562.         (void) bflush();
  563.  
  564.     assert(que == ZOMBIE_Q || que == TSR_Q);
  565.  
  566.     if (curproc->pid == 0) {
  567.         FATAL("attempt to terminate MiNT");
  568.     }
  569.  
  570. /* cancel all pending timeouts for this process */
  571.     cancelalltimeouts();
  572. /* cancel alarm clock */
  573.     curproc->alarmtim = 0;
  574.  
  575. /* release any drives locked by Dlock */
  576.     for(i = 0; i < NUM_DRIVES; i++) {
  577.         if (dlockproc[i] == curproc) {
  578.             dlockproc[i] = 0;
  579.             changedrv(i);
  580.         }
  581.     }
  582.  
  583. /* release the controlling terminal, if we're a process group leader */
  584.     fp = curproc->handle[-1];
  585.     if (fp && is_terminal(fp) && curproc->pgrp == curproc->pid) {
  586.         struct tty *tty = (struct tty *)fp->devinfo;
  587.         if (curproc->pgrp == tty->pgrp)
  588.             tty->pgrp = 0;
  589.     }
  590.  
  591. /* close all files */
  592.     for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  593.         if ((fp = curproc->handle[i]) != 0)
  594.             do_close(fp);
  595.         curproc->handle[i] = 0;
  596.     }
  597.  
  598. /* close any unresolved Fsfirst/Fsnext directory searches */
  599.     for (i = 0; i < NUM_SEARCH; i++) {
  600.         if (curproc->srchdta[i]) {
  601.             DIR *dirh = &curproc->srchdir[i];
  602.             (*dirh->fc.fs->closedir)(dirh);
  603.         }
  604.     }
  605.  
  606. /* release all semaphores owned by this process */
  607.     free_semaphores(curproc->pid);
  608.  
  609. /* free all memory */
  610.     if (que == ZOMBIE_Q) {
  611.         for (i = curproc->num_reg - 1; i >=0; i--) {
  612.             m = curproc->mem[i];
  613.             curproc->mem[i] = 0; curproc->addr[i] = 0;
  614.             if (m) {
  615.         /* don't free specially allocated memory */
  616.                 if (m->mflags & M_KEEP) {
  617.                     if (curproc != rootproc)
  618.                         attach_region(rootproc, m);
  619.                 }
  620.                 m->links--;
  621.                 if (m->links == 0) {
  622.                     free_region(m);
  623.                 }
  624.             }
  625.         }
  626.         kfree(curproc->mem); kfree(curproc->addr);
  627.         curproc->mem = 0;
  628.         curproc->addr = 0;
  629.         curproc->num_reg = 0;
  630.     }
  631. /*    else
  632.          make TSR process non-swappable */
  633.  
  634. /*
  635.  * make sure that any open files that refer to this process are
  636.  * closed
  637.  */
  638.     changedrv(PROC_BASE_DEV | curproc->pid);
  639.  
  640. /* find our parent (if parent not found, then use process 0 as parent
  641.  * since that process is constantly in a wait loop)
  642.  */
  643.  
  644.     p = pid2proc(curproc->ppid);
  645.     if (!p) {
  646.         TRACE(("terminate: parent not found"));
  647.         p = pid2proc(0);
  648.     }
  649.  
  650. /* NOTE: normally just post_sig is sufficient for sending a signal; but
  651.  * in this particular case, we have to worry about processes that are
  652.  * blocking all signals because they Vfork'd and are waiting for us to
  653.  * finish (which is indicated by a wait_cond matching our PROC
  654.  * structure), and also processes that are ignoring SIGCHLD but are
  655.  * waiting for us.
  656.  */
  657.     if (p->wait_q == WAIT_Q && 
  658.         (p->wait_cond == (long)curproc || p->wait_cond == (long)p_waitpid) ) {
  659.         TRACE(("terminate: waking up parent"));
  660.         rm_q(WAIT_Q, p);
  661.         add_q(READY_Q, p);
  662.     }
  663.     if (curproc->ptracer && curproc->ptracer != p) {
  664.         /* BUG: should we ensure curproc->ptracer is awake ? */
  665.         post_sig(curproc->ptracer, SIGCHLD);    /* tell tracing process */
  666.     }
  667.     post_sig(p, SIGCHLD);        /* inform of process termination */
  668.  
  669. /* find our children, and orphan them
  670.  * also, check for processes we were tracing, and
  671.  * cancel the trace
  672.  */
  673.     i = curproc->pid;
  674.     for (p = proclist; p; p = p->gl_next) {
  675.         if (p->ppid == i) {
  676.             p->ppid = 0;    /* have the system adopt it */
  677.             if (p->wait_q == ZOMBIE_Q) 
  678.                 wakemint = 1;    /* we need to wake proc. 0 */
  679.         }
  680.         if (p->ptracer == curproc) {
  681.             p->ptracer = 0;
  682. /*
  683.  * `FEATURE': we terminate traced processes when the tracer terminates.
  684.  * It might plausibly be argued that it would be better to let them
  685.  * continue, to let some (new) tracer take them over. On the other hand,
  686.  * if the tracer terminated normally, it should have used Fcntl(PTRACESFLAGS)
  687.  * to reset the trace nicely, so something must be wrong for us to have
  688.  * reached here.
  689.  */
  690.             post_sig(p, SIGTERM);    /* arrange for termination */
  691.         }
  692.     }
  693.  
  694.     if (wakemint) {
  695.         p = rootproc;        /* pid 0 */
  696.         if (p->wait_q == WAIT_Q) {
  697.             rm_q(WAIT_Q, p);
  698.             add_q(READY_Q, p);
  699.         }
  700.     }
  701.  
  702. /* this makes sure that our children are inherited by the system;
  703.  * plus, it may help avoid problems if somehow a signal gets
  704.  * through to us
  705.  */
  706.     for(i = 0; i < NSIG; i++)
  707.         curproc->sighandle[i] = SIG_IGN;
  708.  
  709. /* finally, reset the time/date stamp for u:\proc */
  710.     proctime = timestamp;
  711.     procdate = datestamp;
  712.  
  713.     sleep(que, (long)(unsigned)code);
  714.  
  715. /* we shouldn't ever get here */
  716.     FATAL("terminate: sleep woke up when it shouldn't have");
  717.     return 0;
  718. }
  719.  
  720. /*
  721.  * TOS process termination entry points:
  722.  * p_term terminates the process, freeing its memory
  723.  * p_termres lets the process hang around resident in memory, after
  724.  * shrinking its transient program area to "save" bytes
  725.  */
  726.  
  727. long ARGS_ON_STACK
  728. p_term(code)
  729.     int code;
  730. {
  731.     CONTEXT *syscall;
  732.  
  733.     TRACE(("Pterm(%d)", code));
  734. /* call the process termination vector */
  735.     syscall = &curproc->ctxt[SYSCALL];
  736.  
  737.     if (syscall->term_vec != (long)rts) {
  738.         TRACE(("term_vec: user has something to do"));
  739. /*
  740.  * we handle the termination vector just like Supexec(), by
  741.  * sending signal 0 to the process. See supexec() in xbios.c for details.
  742.  * Note that we _always_ want to unwind the signal stack, and setting
  743.  * bit 1 of curproc->sigmask tells handle_sig to do that -- see signal.c.
  744.  */
  745.         curproc->sigmask |= 1L;
  746.         (void)supexec((Func)syscall->term_vec, 0L, 0L, 0L, 0L, 
  747.                 (long)code);
  748. /*
  749.  * if we arrive here, continue with the termination...
  750.  */
  751.     }
  752.     return terminate(code, ZOMBIE_Q);
  753. }
  754.  
  755. long ARGS_ON_STACK
  756. p_term0()
  757. {
  758.     return p_term(0);
  759. }
  760.  
  761. long ARGS_ON_STACK
  762. p_termres(save, code)
  763.     long save;
  764.     int code;
  765. {
  766.     MEMREGION *m;
  767.  
  768.     TRACE(("Ptermres(%ld, %d)", save, code));
  769.     m = curproc->mem[1];    /* should be the basepage (0 is env.) */
  770.     if (m) {
  771.         (void)shrink_region(m, save);
  772.     }
  773.     return terminate(code, TSR_Q);
  774. }
  775.  
  776. /*
  777.  * routine for waiting for children to die. Return has the pid of the
  778.  * found child in the high word, and the child's exit code in
  779.  * the low word. If no children exist, return "File Not Found".
  780.  * If (nohang & 1) is nonzero, then return a 0 immediately if we have
  781.  * no dead children but some living ones that we still have to wait
  782.  * for. If (nohang & 2) is nonzero, then we return any stopped
  783.  * children; otherwise, only children that have exited or are stopped
  784.  * due to a trace trap are returned.
  785.  * If "rusage" is non-zero and a child is found, put the child's
  786.  * resource usage into it (currently only the user and system time are
  787.  * sent back).
  788.  * The pid argument specifies a set of child processes for which status
  789.  * is requested:
  790.  *     If pid is equal to -1, status is requested for any child process.
  791.  *
  792.  *    If pid is greater than zero, it specifies the process ID of a
  793.  *    single child process for which status is requested.
  794.  *
  795.  *    If pid is equal to zero, status is requested for any child
  796.  *    process whose process group ID is equal to that of the calling
  797.  *    process.
  798.  *
  799.  *    If pid is less than -1, status is requested for any child process
  800.  *    whose process group ID is equal to the absolute value of pid.
  801.  *
  802.  * Note this call is a real standard crosser... POSIX.1 doesn't have the
  803.  * rusage stuff, BSD doesn't have the pid stuff; both are useful, so why
  804.  * not have it all!
  805.  */
  806.  
  807. long ARGS_ON_STACK
  808. p_waitpid(pid, nohang, rusage)
  809.     int pid;
  810.     int nohang;
  811.     long *rusage;
  812. {
  813.     long r;
  814.     PROC *p, *q;
  815.     int ourpid;
  816.     int found;
  817.  
  818.     TRACE(("Pwaitpid(%d, %d, %lx)", pid, nohang, rusage));
  819.     ourpid = curproc->pid;
  820.  
  821. /* if there are terminated children, clean up and return their info;
  822.  * if there are children, but still running, wait for them;
  823.  * if there are no children, return an error
  824.  */
  825.  
  826.     do {
  827. /* look for any children */
  828.         found = 0;
  829.         for (p = proclist; p; p = p->gl_next) {
  830.             if ((p->ppid == ourpid || p->ptracer == curproc) &&
  831.                 (pid == -1 ||
  832.                 (pid > 0 && pid == p->pid) ||
  833.                 (pid == 0 && p->pgrp == ourpid) ||
  834.                 (pid < -1 && p->pgrp == -pid))) {
  835.                 found++;
  836.                 if (p->wait_q == ZOMBIE_Q || p->wait_q == TSR_Q)
  837.                     break;
  838.  
  839. /* p->wait_cond == 0 if a stopped process has already been waited for */
  840.                 if (p->wait_q == STOP_Q && p->wait_cond) {
  841.                     if ((nohang & 2) ||
  842.                     ((p->wait_cond&0x1f00) == (SIGTRAP<<8)))
  843.                         break;
  844.                 }
  845.             }
  846.         }
  847.         if (!p) {
  848.             if (found) {
  849.                 if (nohang & 1)
  850.                     return 0;
  851.                 if (curproc->pid)
  852.                     TRACE(("Pwaitpid: going to sleep"));
  853.                 sleep(WAIT_Q, (long)p_waitpid);
  854.             }
  855.             else {
  856.                 DEBUG(("Pwaitpid: no children found"));
  857.                 return EFILNF;
  858.             }
  859.         }
  860.     } while (!p);
  861.  
  862. /* OK, we've found our child */
  863. /* calculate the return code from the child's exit code and pid */
  864.     r = (((unsigned long)p->pid) << 16) | (p->wait_cond & 0x0000ffff);
  865.  
  866. /* check resource usage */
  867.     if (rusage) {
  868.         *rusage++ = p->usrtime;
  869.         *rusage = p->systime;
  870.     }
  871.  
  872. /* avoid adding adopted trace processes usage to the foster parent */
  873.     if (curproc->pid == p->ppid) {
  874.     /* add child's resource usage to parent's */
  875.         if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q) {
  876.             curproc->chldstime += p->systime;
  877.             curproc->chldutime += p->usrtime;
  878.         }
  879.     }
  880.  
  881. /* if it was stopped, mark it as having been found and again return */
  882.     if (p->wait_q == STOP_Q) {
  883.         p->wait_cond = 0;
  884.         return r;
  885.     }
  886.  
  887. /* We have to worry about processes which attach themselves to running
  888.  * processes which they want to trace. We fix things up so that the
  889.  * second time the signal gets delivered we will go all the way to the
  890.  * end of this function.
  891.  */
  892.      if (p->ptracer && p->ptracer->pid != p->ppid) {
  893.         if (curproc == p->ptracer) {
  894.         /* deliver the signal to the tracing process first */
  895.             TRACE(("Pwaitpid(ptracer): returning status to tracing process"));
  896.             p->ptracer = NULL;
  897.             return r;
  898.         }
  899.         else {
  900.         /* Hmmm, the real parent got here first */
  901.             TRACE(("Pwaitpid(ptracer): returning status to parent process"));
  902.             p->ppid = -1;
  903.             return r;
  904.         }
  905.     }
  906.     
  907. /* if it was a TSR, mark it as having been found and return */
  908.     if (p->wait_q == TSR_Q) {
  909.         p->ppid = -1;
  910.         return r;
  911.     }
  912.  
  913. /* it better have been on the ZOMBIE queue from here on in... */
  914.     assert(p->wait_q == ZOMBIE_Q);
  915.     assert(p != curproc);
  916.  
  917. /* take the child off both the global and ZOMBIE lists */
  918.     rm_q(ZOMBIE_Q, p);
  919.  
  920.     if (proclist == p) {
  921.         proclist = p->gl_next;
  922.         p->gl_next = 0;
  923.     }
  924.     else {
  925.         q = proclist;
  926.         while(q && q->gl_next != p)
  927.             q = q->gl_next;
  928.         assert(q);
  929.         q->gl_next = p->gl_next;
  930.         p->gl_next = 0;
  931.     }
  932.  
  933.     dispose_proc(p);    /* free the PROC structure */
  934.  
  935.     return r;
  936. }
  937.  
  938. /* p_wait3: BSD process termination primitive, here to maintain
  939.  * compatibility with existing binaries.
  940.  */
  941. long ARGS_ON_STACK
  942. p_wait3(nohang, rusage)
  943.     int nohang;
  944.     long *rusage;
  945. {
  946.     return p_waitpid(-1, nohang, rusage);
  947. }
  948.  
  949. /* p_wait: block until a child has exited, and don't worry about
  950.    resource stats. this is provided as a convenience, and to maintain
  951.    compatibility with existing binaries (yes, I'm lazy...). we could
  952.    make do with Pwaitpid().
  953.  */
  954.  
  955. long ARGS_ON_STACK
  956. p_wait()
  957. {
  958. /*
  959.  * BEWARE:
  960.  * POSIX says that wait() should be implemented as
  961.  * Pwaitpid(-1, 0, (long *)0). Pwait is really not
  962.  * useful for much at all, but we'll keep it around
  963.  * for a while (with it's old, crufty semantics)
  964.  * for backwards compatibility. People implementing
  965.  * POSIX style libraries should use Pwaitpid even
  966.  * to implement wait().
  967.  */
  968.     return p_wait3(2, (long *)0);
  969. }
  970.  
  971. /*
  972.  * do_vfork(save): create a duplicate of  the current process. This is
  973.  * essentially a vfork() algorithm, except that if (save == 1) the
  974.  * parent's address space is saved, and then restored when the process
  975.  * is made runnable again. The parent is suspended until either the child
  976.  * process (the duplicate) exits or does a Pexec which overlays its
  977.  * memory space.
  978.  *
  979.  * "txtsize" is the size of the process' TEXT area, if it has a valid one;
  980.  * this is part of the second memory region attached (the basepage one)
  981.  * and need not be saved (we assume processes don't write on their own
  982.  * code segment)
  983.  */
  984.  
  985. static long
  986. do_vfork(save)
  987.     int save;
  988. {
  989.     PROC *p;
  990.     long sigmask;
  991.     MEMREGION *m, *savemem = 0;
  992.     long savesize, txtsize;
  993.     int i;
  994.     char *saveplace;
  995.  
  996.     p = fork_proc();
  997.     if (!p) {
  998.         DEBUG(("do_vfork: couldn't get new PROC struct"));
  999.         return mint_errno;
  1000.     }
  1001. /* set u:\proc time+date */
  1002.     proctime = timestamp;
  1003.     procdate = datestamp;
  1004.  
  1005. /*
  1006.  * maybe save the parent's address space
  1007.  */
  1008.     txtsize = p->txtsize;
  1009.  
  1010.     if (save) {
  1011.         TRACE(("do_vfork: saving parent"));
  1012.         savesize = memused(curproc) - txtsize;
  1013.         assert(savesize >= 0);
  1014.  
  1015.         saveplace = (char *)alloc_region(alt, savesize);
  1016.         if (!saveplace)
  1017.             saveplace = (char *)alloc_region(core, savesize);
  1018.  
  1019.         if (!saveplace) {
  1020.             DEBUG(("do_vfork: can't save parent's memory"));
  1021.             p->ppid = 0;        /* abandon the child */
  1022.             post_sig(p, SIGKILL);    /* then kill it */
  1023.             p->ctxt[CURRENT].pc = (long)check_sigs;
  1024.                 /* just to make sure it dies */
  1025.             p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
  1026.             p->pri = MAX_NICE+1;
  1027.             run_next(p, 1);
  1028.             yield();
  1029.             return ENSMEM;
  1030.         }
  1031.         savemem = addr2mem((virtaddr)saveplace);
  1032.         assert(savemem);
  1033.         for (i = 0; i < curproc->num_reg; i++) {
  1034.             m = curproc->mem[i];
  1035.             if (m && m != savemem && !(m->mflags & M_SHTEXT)) {
  1036.                 if (i != 1 || txtsize == 0) {
  1037.                     quickmove(saveplace, (char *)m->loc, m->len);
  1038.                     saveplace += m->len;
  1039.                 }
  1040.                 else {
  1041.                     quickmove(saveplace, (char *)m->loc+txtsize,
  1042.                     m->len - txtsize);
  1043.                     saveplace += m->len - txtsize;
  1044.                 }
  1045.             }
  1046.         }
  1047.     }
  1048.                 
  1049.     p->ctxt[CURRENT] = p->ctxt[SYSCALL];
  1050.     p->ctxt[CURRENT].regs[0] = 0;    /* child returns a 0 from call */
  1051.     p->ctxt[CURRENT].sr &= ~(0x2000); /* child must be in user mode */
  1052. #if 0        /* set up in fork_proc() */
  1053.     p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
  1054. #endif
  1055.  
  1056. /* watch out for job control signals, since our parent can never wake
  1057.  * up to respond to them. solution: block them; exec_region (in mem.c)
  1058.  * clears the signal mask, so an exec() will unblock them.
  1059.  */
  1060.     p->sigmask |= (1L << SIGTSTP) | (1L << SIGTTIN) | (1L << SIGTTOU);
  1061.  
  1062.     TRACE(("do_vfork: parent going to sleep, wait_cond == %lx",
  1063.         (long)p));
  1064.  
  1065. /* WARNING: This sleep() must absolutely not wake up until the child
  1066.  * has released the memory space correctly. That's why we mask off
  1067.  * all signals.
  1068.  */
  1069.     sigmask = curproc->sigmask;
  1070.     curproc->sigmask = ~((unsigned long)1 << SIGKILL);
  1071.  
  1072.     add_q(READY_Q, p);        /* put it on the ready queue */
  1073.     sleep(WAIT_Q, (long)p);            /* while we wait for it */
  1074.     TRACE(("do_vfork: parent waking up"));
  1075.  
  1076.     if (save) {
  1077.         TRACE(("do_vfork: parent restoring memory"));
  1078.         saveplace = (char *)savemem->loc;
  1079.         for (i = 0; i < curproc->num_reg; i++) {
  1080.             m = curproc->mem[i];
  1081.             if (m && (m != savemem) && !(m->mflags & M_SHTEXT)) {
  1082.                 if (i != 1 || txtsize == 0) {
  1083.                     quickmove((char *)m->loc, saveplace, m->len);
  1084.                     saveplace += m->len;
  1085.                 }
  1086.                 else {
  1087.                     quickmove((char *)m->loc+txtsize, saveplace,
  1088.                     m->len - txtsize);
  1089.                     saveplace += m->len - txtsize;
  1090.                 }
  1091.             }
  1092.         }
  1093.         detach_region(curproc, savemem);
  1094.     }
  1095.     curproc->sigmask = sigmask;
  1096.     check_sigs();    /* did we get any signals while sleeping? */
  1097.     return p->pid;
  1098. }
  1099.  
  1100. /*
  1101.  * here are the interfaces that the user sees. Pvfork() doesn't save
  1102.  * the child's address space; Pfork() does. Someday Pfork() should
  1103.  * allow asynchronous execution of both child and parent, but this
  1104.  * will do for now.
  1105.  */
  1106.  
  1107. long ARGS_ON_STACK
  1108. p_vfork()
  1109. {
  1110.     return do_vfork(0);
  1111. }
  1112.  
  1113. long ARGS_ON_STACK
  1114. p_fork()
  1115. {
  1116.     return do_vfork(1);
  1117. }
  1118.